<table-submenu></table-submenu>

<div class="content-section introduction">
    <div>
        <span class="feature-title">TurboTable</span>
        <span>Table is the successor of p-dataTable with a lightning fast performance (at least 10x faster) and excellent level of control over the presentation. p-table is called as TurboTable in order to differantiate if from the deprecated p-dataTable.
        </span>
    </div>
</div>

<div class="content-section implementation">
    <h3 class="first">Basic</h3>
    <p-table [value]="cars">
        <ng-template pTemplate="header">
            <tr>
                <th>Vin</th>
                <th>Year</th>
                <th>Brand</th>
                <th>Color</th>
            </tr>
        </ng-template>
        <ng-template pTemplate="body" let-car>
            <tr>
                <td>{{car.vin}}</td>
                <td>{{car.year}}</td>
                <td>{{car.brand}}</td>
                <td>{{car.color}}</td>
            </tr>
        </ng-template>
    </p-table>

    <h3>Dynamic Columns</h3>
    <p-table [columns]="cols" [value]="cars">
        <ng-template pTemplate="header" let-columns>
            <tr>
                <th *ngFor="let col of columns">
                    {{col.header}}
                </th>
            </tr>
        </ng-template>
        <ng-template pTemplate="body" let-rowData let-columns="columns">
            <tr>
                <td *ngFor="let col of columns">
                     {{rowData[col.field]}}
                </td>
            </tr>
        </ng-template>
    </p-table>
</div>

<div class="content-section documentation">
    <p-tabView effect="fade">
        <p-tabPanel header="Documentation">
            <h3>Import</h3>
<pre>
<code class="language-typescript" pCode ngNonBindable>
import &#123;TableModule&#125; from 'primeng/table';
</code>
</pre>

            <h3>Getting Started</h3>
            <p>Table requires a value as an array of objects and templates for the presentation. Throughout the samples, a car interface having
            vin, brand, year and color properties is used to define an object to be displayed by the table. Cars are loaded by a CarService that
            connects to a server to fetch the data.</p>
<pre>
<code class="language-typescript" pCode ngNonBindable>
export interface Car &#123;
    vin;
    year;
    brand;
    color;
&#125;
</code>
</pre>

<pre>
<code class="language-typescript" pCode ngNonBindable>
import &#123; HttpClient &#125; from '@angular/common/http';
import &#123; Injectable &#125; from '@angular/core';

import &#123; Car &#125; from '../domain/car';

@Injectable()
export class CarService &#123;

    constructor(private http: HttpClient) &#123;&#125;

    getCarsSmall() &#123;
        return this.http.get('/showcase/resources/data/cars-small.json')
                    .toPromise()
                    .then(res => &lt;Car[]&gt; res.data)
                    .then(data => &#123; return data; &#125;);
    &#125;
&#125;
</code>
</pre>
            <p>Following sample has a table of 4 columns and retrieves the data from a service on ngOnInit.</p>

<pre>
<code class="language-typescript" pCode ngNonBindable>
export class DataTableDemo implements OnInit &#123;

    cars: Car[];

    constructor(private carService: CarService) &#123; &#125;

    ngOnInit() &#123;
        this.carService.getCarsSmall().then(cars => this.cars = cars);
    &#125;
&#125;
</code>
</pre>

        <p>List of cars are bound to the value property whereas <i>header</i> and <i>body</i> templates are used to define the content of these sections.</p>
<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [value]="cars"&gt;
    &lt;ng-template pTemplate="header"&gt;
        &lt;tr&gt;
            &lt;th&gt;Vin&lt;/th&gt;
            &lt;th&gt;Year&lt;/th&gt;
            &lt;th&gt;Brand&lt;/th&gt;
            &lt;th&gt;Color&lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-car&gt;
        &lt;tr&gt;
            &lt;td&gt;&#123;&#123;car.vin&#125;&#125;&lt;/td&gt;
            &lt;td&gt;&#123;&#123;car.year&#125;&#125;&lt;/td&gt;
            &lt;td&gt;&#123;&#123;car.brand&#125;&#125;&lt;/td&gt;
            &lt;td&gt;&#123;&#123;car.color&#125;&#125;&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>

        <h3>Dynamic Columns</h3>
        <p>Instead of configuring columns one by one, a simple ngFor can be used to implement dynamic columns. cols property below is an array of objects that represent a column,
            only property that table component uses is field, rest of the properties like header depend on your choice.
        </p>
<pre>
<code class="language-typescript" pCode ngNonBindable>
export class DynamicColumnsDemo implements OnInit &#123;

    cars: Car[];

    cols: any[];

    constructor(private carService: CarService) &#123; &#125;

    ngOnInit() &#123;
        this.carService.getCarsSmall().then(cars => this.cars = cars);

        this.cols = [
            &#123; field: 'vin', header: 'Vin' &#125;,
            &#123; field: 'year', header: 'Year' &#125;,
            &#123; field: 'brand', header: 'Brand' &#125;,
            &#123; field: 'color', header: 'Color' &#125;
        ];
    &#125;
&#125;
</code>
</pre>

        <p>There are two ways to render dynamic columns, since cols property is in the scope of component you can just simply bind it to ngFor directive to generate the structure.</p>

<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [value]="cars"&gt;
    &lt;ng-template pTemplate="header"&gt;
        &lt;tr&gt;
            &lt;th *ngFor="let col of cols"&gt;
                &#123;&#123;col.header&#125;&#125;
            &lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-car&gt;
        &lt;tr&gt;
            &lt;td *ngFor="let col of cols"&gt;
                    &#123;&#123;car[col.field]&#125;&#125;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>

            <p>Other alternative is binding the cols array to the columns property and then defining a template variable to access it within your templates.
                There are 3 cases where this is required which are csv export, reorderable columns and global filtering without the globalFilterFields property.
            </p>
<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [columns]="cols" [value]="cars"&gt;
    &lt;ng-template pTemplate="header" let-columns&gt;
        &lt;tr&gt;
            &lt;th *ngFor="let col of columns"&gt;
                &#123;&#123;col.header&#125;&#125;
            &lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-car let-columns="columns"&gt;
        &lt;tr&gt;
            &lt;td *ngFor="let col of columns"&gt;
                    &#123;&#123;car[col.field]&#125;&#125;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>

            <p>Tip: Use ngSwitch to customize the column content per dynamic column.</p>

            <h3>Table Layout</h3>
            <p>For performance reasons, default table-layout is fixed meaning the cell widths do not depend on their content. If you require cells to scale based on their contents
                set <i>autoLayout</i> property to true. Note that Scrollable and/or Resizable tables do not support auto layout due to technical reasons.
            </p>

            <h3>Templates</h3>
            <p>Table is a template driven component with named templates such as header and body that we've used so far. Templates grant a great level of customization and flexibility
                where you have total control over the presentation while table handles the features such as paging, sorting, filtering and more. This speeds up development without sacrifing
                flexibility. Here is the full list of available templates.</p>

            <div class="doc-tablewrapper">
                <table class="doc-table">
                    <thead>
                        <tr>
                            <th>Name</th>
                            <th>Parameters</th>
                            <th>Description</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td>caption</td>
                            <td>-</td>
                            <td>Caption content of the table.</td>
                        </tr>
                        <tr>
                            <td>header</td>
                            <td>$implicit: Columns</td>
                            <td>Content of the thead element.</td>
                        </tr>
                        <tr>
                            <td>body</td>
                            <td>$implicit: Data of the row <br>
                                rowIndex: Index of the row <br>
                                columns: Columns collection <br>
                                expanded: Whether the row is expanded
                            </td>
                            <td>Content of the tbody element.</td>
                        </tr>
                        <tr>
                            <td>footer</td>
                            <td>$implicit: Columns</td>
                            <td>Content of the tfoot element.</td>
                        </tr>
                        <tr>
                            <td>summary</td>
                            <td>-</td>
                            <td>Summary section to display below the table.</td>
                        </tr>
                        <tr>
                            <td>colgroup</td>
                            <td>$implicit: Columns</td>
                            <td>ColGroup element of the table to customize columns.</td>
                        </tr>
                        <tr>
                            <td>rowexpansion</td>
                            <td>$implicit: Data of the row <br>
                                rowIndex: Index of the row <br>
                                columns: Columns collection <br>
                            </td>
                            <td>Content of an extended row.</td>
                        </tr>
                        <tr>
                            <td>frozenrows</td>
                            <td>$implicit: Data of the row <br>
                                rowIndex: Index of the row <br>
                                columns: Columns collection<br>
                            </td>
                            <td>Content of the tbody element to display frozen rows.</td>
                        </tr>
                        <tr>
                            <td>frozenheader</td>
                            <td>$implicit: Columns</td>
                            <td>Content of the thead element in frozen side.</td>
                        </tr>
                        <tr>
                            <td>frozenbody</td>
                            <td>$implicit: Data of the row <br>
                                rowIndex: Index of the row <br>
                                columns: Columns collection <br>
                            </td>
                            <td>Content of the tbody element in frozen side.</td>
                        </tr>
                        <tr>
                            <td>frozenfooter</td>
                            <td>$implicit: Columns</td>
                            <td>Content of the tfoot element in frozen side.</td>
                        </tr>
                        <tr>
                            <td>frozencolgroup</td>
                            <td>$implicit: Columns</td>
                            <td>ColGroup element of the table to customize frozen columns.</td>
                        </tr>
                        <tr>
                            <td>emptymessage</td>
                            <td>$implicit: Columns</td>
                            <td>Content to display when there is no value to display.</td>
                        </tr>
                        <tr>
                            <td>paginatorleft</td>
                            <td>state: $implicit
                                state.page: Current page<br />
                                state.rows: Rows per page<br />
                                state.first: Index of the first records<br />
                                state.totalRecords: Number of total records<br />
                            </td>
                            <td>Custom content for the left section of the paginator.</td>
                        </tr>
                        <tr>
                            <td>paginatorright</td>
                            <td>state: $implicit
                                state.page: Current page<br />
                                state.rows: Rows per page<br />
                                state.first: Index of the first records<br />
                                state.totalRecords: Number of total records<br />
                            </td>
                            <td>Custom content for the right section of the paginator.</td>
                        </tr>
                    </tbody>
                </table>
            </div>

            <h3>Change Detection</h3>
            <p>Table may need to be aware of changes in its value in some cases such as reapplying sort. For the sake of performance, this is only done when the reference of the value changes meaning a
                setter is used instead of ngDoCheck/IterableDiffers which can reduce performance. So when you manipulate the value such as removing or adding an item, instead of using array methods such as push, splice
                create a new array reference using a spread operator or similar.
            </p>

            <h3>Sections</h3>
            <p>Table offers various templates to display additional information about the data such as a caption or summary.</p>

 <pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [columns]="cols" [value]="cars"&gt;
    &lt;ng-template pTemplate="caption"&gt;
        List of Cars
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="header" let-columns&gt;
        &lt;tr&gt;
            &lt;th *ngFor="let col of columns"&gt;
                &#123;&#123;col.header&#125;&#125;
            &lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-rowData let-columns="columns"&gt;
        &lt;tr&gt;
            &lt;td *ngFor="let col of columns"&gt;
            &#123;&#123;rowData[col.field]&#125;&#125;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="footer" let-columns&gt;
        &lt;tr&gt;
            &lt;td *ngFor="let col of columns"&gt;
            &#123;&#123;col.header&#125;&#125;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="summary"&gt;
        There are &#123;&#123;cars?.length&#125;&#125; cars
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>
            <p>See the <a [routerLink]="['/table/sections']">live example.</a></p>

            <h3>Column Grouping</h3>
            <p>Columns can easily be grouped using templating. Let's start with sample data of sales of brands per year.</p>
<pre>
<code class="language-typescript" pCode ngNonBindable>
export class TableColGroupDemo implements OnInit &#123;

    sales: any[];

    ngOnInit() &#123;
        this.sales = [
            &#123; brand: 'Apple', lastYearSale: '51%', thisYearSale: '40%', lastYearProfit: '$54,406.00', thisYearProfit: '$43,342' &#125;,
            &#123; brand: 'Samsung', lastYearSale: '83%', thisYearSale: '96%', lastYearProfit: '$423,132', thisYearProfit: '$312,122' &#125;,
            &#123; brand: 'Microsoft', lastYearSale: '38%', thisYearSale: '5%', lastYearProfit: '$12,321', thisYearProfit: '$8,500' &#125;,
            &#123; brand: 'Philips', lastYearSale: '49%', thisYearSale: '22%', lastYearProfit: '$745,232', thisYearProfit: '$650,323,' &#125;,
            &#123; brand: 'Song', lastYearSale: '17%', thisYearSale: '79%', lastYearProfit: '$643,242', thisYearProfit: '500,332' &#125;,
            &#123; brand: 'LG', lastYearSale: '52%', thisYearSale: ' 65%', lastYearProfit: '$421,132', thisYearProfit: '$150,005' &#125;,
            &#123; brand: 'Sharp', lastYearSale: '82%', thisYearSale: '12%', lastYearProfit: '$131,211', thisYearProfit: '$100,214' &#125;,
            &#123; brand: 'Panasonic', lastYearSale: '44%', thisYearSale: '45%', lastYearProfit: '$66,442', thisYearProfit: '$53,322' &#125;,
            &#123; brand: 'HTC', lastYearSale: '90%', thisYearSale: '56%', lastYearProfit: '$765,442', thisYearProfit: '$296,232' &#125;,
            &#123; brand: 'Toshiba', lastYearSale: '75%', thisYearSale: '54%', lastYearProfit: '$21,212', thisYearProfit: '$12,533' &#125;
        ];
    &#125;
&#125;
</code>
</pre>

<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [value]="sales"&gt;
    &lt;ng-template pTemplate="header"&gt;
        &lt;tr&gt;
            &lt;th rowspan="3"&gt;Brand&lt;/th&gt;
            &lt;th colspan="4"&gt;Sale Rate&lt;/th&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;th colspan="2"&gt;Sales&lt;/th&gt;
            &lt;th colspan="2"&gt;Profits&lt;/th&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;th&gt;Last Year&lt;/th&gt;
            &lt;th&gt;This Year&lt;/th&gt;
            &lt;th&gt;Last Year&lt;/th&gt;
            &lt;th&gt;This Year&lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-sale&gt;
        &lt;tr&gt;
            &lt;td&gt;&#123;&#123;sale.brand&#125;&#125;&lt;/td&gt;
            &lt;td&gt;&#123;&#123;sale.lastYearSale&#125;&#125;&lt;/td&gt;
            &lt;td&gt;&#123;&#123;sale.thisYearSale&#125;&#125;&lt;/td&gt;
            &lt;td&gt;&#123;&#123;sale.lastYearProfit&#125;&#125;&lt;/td&gt;
            &lt;td&gt;&#123;&#123;sale.thisYearProfit&#125;&#125;&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="footer"&gt;
        &lt;tr&gt;
            &lt;td colspan="3"&gt;Totals&lt;/td&gt;
            &lt;td&gt;$506,202&lt;/td&gt;
            &lt;td&gt;$531,020&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>
            <p>See the <a [routerLink]="['/table/colgroup']">live example.</a></p>

            <h3>Row Grouping</h3>
            <p>Templating features can also be used to implement row grouping functionality, here is an example implementation that uses a metadata object
                to keep at what index a group starts and how many items it has.</p>
<pre>
<code class="language-typescript" pCode ngNonBindable>
export class TableRowGroupDemo implements OnInit &#123;

    cars: Car[];

    rowGroupMetadata: any;

    constructor(private carService: CarService) &#123; &#125;

    ngOnInit() &#123;
        this.carService.getCarsMedium().then(cars => &#123;
            this.cars = cars;
            this.updateRowGroupMetaData();
        &#125;);
    &#125;

    onSort() &#123;
        this.updateRowGroupMetaData();
    &#125;

    updateRowGroupMetaData() &#123;
        this.rowGroupMetadata = &#123;&#125;;
        if (this.cars) &#123;
            for (let i = 0; i &lt; this.cars.length; i++) &#123;
                let rowData = this.cars[i];
                let brand = rowData.brand;
                if (i == 0) &#123;
                    this.rowGroupMetadata[brand] = &#123; index: 0, size: 1 &#125;;
                &#125;
                else &#123;
                    let previousRowData = this.cars[i - 1];
                    let previousRowGroup = previousRowData.brand;
                    if (brand === previousRowGroup)
                        this.rowGroupMetadata[brand].size++;
                    else
                        this.rowGroupMetadata[brand] = &#123; index: i, size: 1 &#125;;
                &#125;
            &#125;
        &#125;
    &#125;

&#125;
</code>
</pre>

            <p>Using this metadata rows can be grouped using a subheader that displays the group. Note that grouped data should be sorted so enable sortField
            so that table applies sorting before grouping if your data is not sorted.</p>

<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [value]="cars" sortField="brand" sortMode="single" (onSort)="onSort()"&gt;
    &lt;ng-template pTemplate="header"&gt;
        &lt;tr&gt;
            &lt;th&gt;Vin&lt;/th&gt;
            &lt;th&gt;Year&lt;/th&gt;
            &lt;th&gt;Color&lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-rowData let-rowIndex="rowIndex"&gt;
        &lt;tr class="ui-widget-header" *ngIf="rowGroupMetadata[rowData.brand].index === rowIndex"&gt;
            &lt;td colspan="3"&gt;
                &lt;span style="font-weight:bold"&gt;&#123;&#123;rowData.brand&#125;&#125;&lt;/span&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;&#123;&#123;rowData.vin&#125;&#125;&lt;/td&gt;
            &lt;td&gt;&#123;&#123;rowData.year&#125;&#125;&lt;/td&gt;
            &lt;td&gt;&#123;&#123;rowData.color&#125;&#125;&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>

<p>An alternative grouping could be using rowspans for the group field.</p>
<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [value]="cars" sortField="brand" sortMode="single" (onSort)="onSort()"&gt;
    &lt;ng-template pTemplate="header"&gt;
        &lt;tr&gt;
            &lt;th&gt;Brand&lt;/th&gt;
            &lt;th&gt;Vin&lt;/th&gt;
            &lt;th&gt;Year&lt;/th&gt;
            &lt;th&gt;Color&lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-rowData let-rowIndex="rowIndex"&gt;
        &lt;tr&gt;
            &lt;td *ngIf="rowGroupMetadata[rowData.brand].index === rowIndex" [attr.rowspan]="rowGroupMetadata[rowData.brand].size"&gt;
                &#123;&#123;rowData.brand&#125;&#125;
            &lt;/td&gt;
            &lt;td&gt;&#123;&#123;rowData.vin&#125;&#125;&lt;/td&gt;
            &lt;td&gt;&#123;&#123;rowData.year&#125;&#125;&lt;/td&gt;
            &lt;td&gt;&#123;&#123;rowData.color&#125;&#125;&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>

            <p>See the <a [routerLink]="['/table/rowgroup']">live example.</a></p>

            <h3>Multi Field grouping</h3>
            <p>Previous example uses a single field to group the rows however nothing limits you to implement multiple field grouping as well. Similarly to single
                grouping, your data should be sorted first, you may use the built-in multiSorting or provide it sorted to the table and create a rowGroupMetadata
                for multiple fields.
            </p>

            <h3>Paginator</h3>
            <p>Pagination is enabled by setting paginator property to true, rows property defines the number of rows per page and pageLinks specify the the number
                of page links to display. See <a [routerLink]="['/paginator']">paginator</a> component for more information.</p>
<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [columns]="cols" [value]="cars" [paginator]="true" [rows]="10"&gt;
    &lt;ng-template pTemplate="header" let-columns&gt;
        &lt;tr&gt;
            &lt;th *ngFor="let col of columns"&gt;
                &#123;&#123;col.header&#125;&#125;
            &lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-rowData let-columns="columns"&gt;
        &lt;tr&gt;
            &lt;td *ngFor="let col of columns"&gt;
                &#123;&#123;rowData[col.field]&#125;&#125;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>

            <p>Paginator can also be controlled via model using a binding to the first property where changes trigger a pagination.</p>
<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [columns]="cols" [value]="cars" [paginator]="true" [rows]="10" [first]="first"&gt;
    &lt;ng-template pTemplate="header" let-columns&gt;
        &lt;tr&gt;
            &lt;th *ngFor="let col of columns"&gt;
                &#123;&#123;col.header&#125;&#125;
            &lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-rowData let-columns="columns"&gt;
        &lt;tr&gt;
            &lt;td *ngFor="let col of columns"&gt;
                &#123;&#123;rowData[col.field]&#125;&#125;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>

<pre>
<code class="language-typescript" pCode ngNonBindable>
export class DataTablePageDemo implements OnInit &#123;

    cars: Car[];

    first: number = 0;

    constructor(private carService: CarService) &#123; &#125;

    ngOnInit() &#123;
        this.carService.getCarsSmall().then(cars => this.cars = cars);
    &#125;

    reset() &#123;
        this.first = 0;
    &#125;
&#125;
</code>
</pre>

            <p>Paginator accepts custom content for the left and the right side via named templates.</p>
<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [columns]="cols" [value]="cars" [paginator]="true" [rows]="10" [first]="first"&gt;
&lt;ng-template pTemplate="header" let-columns&gt;
    &lt;tr&gt;
        &lt;th *ngFor="let col of columns"&gt;
            &#123;&#123;col.header&#125;&#125;
        &lt;/th&gt;
    &lt;/tr&gt;
&lt;/ng-template&gt;
&lt;ng-template pTemplate="body" let-rowData let-columns="columns"&gt;
    &lt;tr&gt;
        &lt;td *ngFor="let col of columns"&gt;
            &#123;&#123;rowData[col.field]&#125;&#125;
        &lt;/td&gt;
    &lt;/tr&gt;
&lt;/ng-template&gt;
&lt;ng-template pTemplate="paginatorleft" let-state&gt;
    &#123;&#123;state.first&#125;&#125;
    &lt;button type="button" pButton icon="fa-refresh"&gt;&lt;/button&gt;
&lt;/ng-template&gt;
&lt;ng-template pTemplate="paginatorright"&gt;
    &lt;button type="button" pButton icon="fa-cloud-upload"&gt;&lt;/button&gt;
&lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>

            <p>Paginator templates gets the paginator state as an implicit variable that provides the following properties</p>
            <ul>
                <li>first</li>
                <li>rows</li>
                <li>page</li>
                <li>totalRecords</li>
            </ul>

            <p>See the <a [routerLink]="['/table/page']">live example.</a></p>

            <h3>Sorting</h3>
            <p>A column can be made sortable by adding the pSortableColumn directive whose value is the field to sort against and a sort indicator via p-sortIcon component. For dynamic columns,
                setting pSortableColumnDisabled property as true disables sorting for that particular column.
            </p>
<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [columns]="cols" [value]="cars1"&gt;
    &lt;ng-template pTemplate="header" let-columns&gt;
        &lt;tr&gt;
            &lt;th *ngFor="let col of columns" [pSortableColumn]="col.field"&gt;
                &#123;&#123;col.header&#125;&#125;
                &lt;p-sortIcon [field]="col.field"&gt;&lt;/p-sortIcon&gt;
            &lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-rowData let-columns="columns"&gt;
        &lt;tr&gt;
            &lt;td *ngFor="let col of columns"&gt;
                &#123;&#123;rowData[col.field]&#125;&#125;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>
            <p>Default sorting is executed on a single column, in order to enable multiple field sorting, set sortMode property to "multiple" and use metakey
            when clicking on another column.</p>
<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [value]="cars" sortMode="multiple"&gt;
</code>
</pre>

            <p>In case you'd like to display the table as sorted by default initially on load, use the sortField-sortOrder properties in single mode.</p>
<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [columns]="cols" [value]="cars1" sortField="year"&gt;
    &lt;ng-template pTemplate="header" let-columns&gt;
        &lt;tr&gt;
            &lt;th *ngFor="let col of columns" [pSortableColumn]="col.field"&gt;
                &#123;&#123;col.header&#125;&#125;
            &lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-rowData let-columns="columns"&gt;
        &lt;tr&gt;
            &lt;td *ngFor="let col of columns"&gt;
                &#123;&#123;rowData[col.field]&#125;&#125;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>
            <p>In multiple mode, use the multiSortMeta property and bind an array of SortMeta objects.</p>
<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [columns]="cols" [value]="cars1" sortMode="multiple" [multiSortMeta]="multiSortMeta"&gt;
    &lt;ng-template pTemplate="header" let-columns&gt;
        &lt;tr&gt;
            &lt;th *ngFor="let col of columns" [pSortableColumn]="col.field"&gt;
                &#123;&#123;col.header&#125;&#125;
            &lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-rowData let-columns="columns"&gt;
        &lt;tr&gt;
            &lt;td *ngFor="let col of columns"&gt;
                &#123;&#123;rowData[col.field]&#125;&#125;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>

<pre>
<code class="language-typescript" pCode ngNonBindable>
this.multiSortMeta = [];
this.multiSortMeta.push(&#123;field: 'year', order: 1&#125;);
this.multiSortMeta.push(&#123;field: 'brand', order: -1&#125;);
</code>
</pre>

            <p>Instead of using the built-in sorting algorithm a custom sort can be attached by enabling customSort property and defining a sortFunction implementation. This function gets a SortEvent instance
                that provides the data to sort, sortField, sortOrder and multiSortMeta.
            </p>
<pre>
<code class="language-typescript" pCode ngNonBindable>
export class CustomTableSortDemo implements OnInit &#123;

    cars: Car[];

    constructor(private carService: CarService) &#123; &#125;

    ngOnInit() &#123;
        this.carService.getCarsSmall().then(cars => this.cars = cars);

        this.cols = [
            &#123; field: 'vin', header: 'Vin' &#125;,
            &#123; field: 'year', header: 'Year' &#125;,
            &#123; field: 'brand', header: 'Brand' &#125;,
            &#123; field: 'color', header: 'Color' &#125;
        ];
    &#125;

    customSort(event: SortEvent) &#123;
        //event.data = Data to sort
        //event.mode = 'single' or 'multiple' sort mode
        //event.field = Sort field in single sort
        //event.order = Sort order in single sort
        //event.multiSortMeta = SortMeta array in multiple sort

        event.data.sort((data1, data2) => &#123;
            let value1 = data1[event.field];
            let value2 = data2[event.field];
            let result = null;

            if (value1 == null && value2 != null)
                result = -1;
            else if (value1 != null && value2 == null)
                result = 1;
            else if (value1 == null && value2 == null)
                result = 0;
            else if (typeof value1 === 'string' && typeof value2 === 'string')
                result = value1.localeCompare(value2);
            else
                result = (value1 < value2) ? -1 : (value1 > value2) ? 1 : 0;

            return (event.order * result);
        &#125;);
    &#125;
&#125;
</code>
</pre>

<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [columns]="cols" [value]="cars" (sortFunction)="customSort($event)" [customSort]="true"&gt;
    &lt;ng-template pTemplate="header" let-columns&gt;
        &lt;tr&gt;
            &lt;th *ngFor="let col of columns" [pSortableColumn]="col.field"&gt;
                &#123;&#123;col.header&#125;&#125;
                &lt;p-sortIcon [field]="col.field"&gt;&lt;/p-sortIcon&gt;
            &lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-rowData let-columns="columns"&gt;
        &lt;tr&gt;
            &lt;td *ngFor="let col of columns"&gt;
                &#123;&#123;rowData[col.field]&#125;&#125;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>

            <p>For screen reader support of sortable headers, use ariaLabel, ariaLabelDesc and ariaLabelAsc properties
                on p-sortIcon component to define aria labels for unsorted, descending and ascending states respectively.</p>

            <p>See the <a [routerLink]="['/table/sort']">live example.</a></p>

            <h3>Filtering</h3>
            <p>Filtering is enabled by defining the filter and calling filter method on the local template variable of the table with value, column field and match mode parameters. Available match modes are
            "startsWith", "contains", "endsWith", "equals", "notEquals", "in", "lt", "lte", "gt" and "gte". Following is an example that utilizes various PrimeNG form components as filters.</p>

            <p>An optional global filter feature is available to search all fields with the same query, to enable this place an input component and call the filterGlobal function with value and match mode properties on your event of choice.</p>
<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table #tt [columns]="cols" [value]="cars" [paginator]="true" [rows]="10"&gt;
    &lt;ng-template pTemplate="caption"&gt;
        &lt;i class="fa fa-search" style="margin:4px 4px 0 0"&gt;&lt;/i&gt;
        &lt;input type="text" pInputText size="50" placeholder="Global Filter" (input)="tt.filterGlobal($event.target.value, 'contains')" style="width:auto"&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="header" let-columns&gt;
        &lt;tr&gt;
            &lt;th *ngFor="let col of columns"&gt;
                &#123;&#123;col.header&#125;&#125;
            &lt;/th&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;th *ngFor="let col of columns" [ngSwitch]="col.field"&gt;
                &lt;input *ngSwitchCase="'vin'" pInputText type="text" (input)="tt.filter($event.target.value, col.field, col.filterMatchMode)"&gt;
                &lt;div *ngSwitchCase="'year'"&gt;
                    &#123;&#123;yearFilter&#125;&#125;
                    &lt;i class="fa fa-close" (click)="yearFilter=null;tt.filter(null, col.field, col.filterMatchMode)"&gt;&lt;/i&gt;
                    &lt;p-slider [style]="&#123;'width':'100%','margin-top':'8px'&#125;" [(ngModel)]="yearFilter" [min]="1970" [max]="2010" (onChange)="onYearChange($event, dt)"&gt;&lt;/p-slider&gt;
                &lt;/div&gt;
                &lt;p-dropdown *ngSwitchCase="'brand'" [options]="brands" [style]="&#123;'width':'100%'&#125;" (onChange)="tt.filter($event.value, col.field, 'equals')"&gt;&lt;/p-dropdown&gt;
                &lt;p-multiSelect *ngSwitchCase="'color'" [options]="colors" defaultLabel="All Colors" (onChange)="tt.filter($event.value, col.field, 'in')"&gt;&lt;/p-multiSelect&gt;
            &lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-rowData let-columns="columns"&gt;
        &lt;tr [pSelectableRow]="rowData"&gt;
            &lt;td *ngFor="let col of columns"&gt;
                &#123;&#123;rowData[col.field]&#125;&#125;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>

<pre>
<code class="language-typescript" pCode ngNonBindable>
export class TableFilterDemo implements OnInit &#123;

    cars: Car[];

    cols: any[];

    brands: SelectItem[];

    colors: SelectItem[];

    yearFilter: number;

    yearTimeout: any;

    constructor(private carService: CarService) &#123; &#125;

    ngOnInit() &#123;
        this.carService.getCarsMedium().then(cars => this.cars = cars);

        this.brands = [
            &#123; label: 'All Brands', value: null &#125;,
            &#123; label: 'Audi', value: 'Audi' &#125;,
            &#123; label: 'BMW', value: 'BMW' &#125;,
            &#123; label: 'Fiat', value: 'Fiat' &#125;,
            &#123; label: 'Honda', value: 'Honda' &#125;,
            &#123; label: 'Jaguar', value: 'Jaguar' &#125;,
            &#123; label: 'Mercedes', value: 'Mercedes' &#125;,
            &#123; label: 'Renault', value: 'Renault' &#125;,
            &#123; label: 'VW', value: 'VW' &#125;,
            &#123; label: 'Volvo', value: 'Volvo' &#125;
        ];

        this.colors = [
            &#123; label: 'White', value: 'White' &#125;,
            &#123; label: 'Green', value: 'Green' &#125;,
            &#123; label: 'Silver', value: 'Silver' &#125;,
            &#123; label: 'Black', value: 'Black' &#125;,
            &#123; label: 'Red', value: 'Red' &#125;,
            &#123; label: 'Maroon', value: 'Maroon' &#125;,
            &#123; label: 'Brown', value: 'Brown' &#125;,
            &#123; label: 'Orange', value: 'Orange' &#125;,
            &#123; label: 'Blue', value: 'Blue' &#125;
        ];

        this.cols = [
            &#123; field: 'vin', header: 'Vin' &#125;,
            &#123; field: 'year', header: 'Year' &#125;,
            &#123; field: 'brand', header: 'Brand' &#125;,
            &#123; field: 'color', header: 'Color' &#125;
        ];
    &#125;

    onYearChange(event, dt) &#123;
        if (this.yearTimeout) &#123;
            clearTimeout(this.yearTimeout);
        &#125;

        this.yearTimeout = setTimeout(() => &#123;
            tt.filter(event.value, 'year', 'gt');
        &#125;, 250);
    &#125;
&#125;
</code>
</pre>

            <p>If you have static columns and need to use global filtering, globalFilterFields property must be defined to configure which fields should be used in global filtering. Another
                use case of this property is to change the fields to utilize in global filtering with dynamic columns.
            </p>
<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [value]="cars" [paginator]="true" [rows]="10" [globalFilterFields]="['vin','year']"&gt;
    //content
&lt;/p-table&gt;
</code>
</pre>

            <p>See the <a [routerLink]="['/table/filter']">live example.</a></p>

            <h3>Selection</h3>
            <p>Table provides built-in single and multiple selection features where selected rows are bound to the selection property and onRowSelect-onRowUnselect events
            are provided as optional callbacks. In order to enable this feature, define a selectionMode, bind a selection reference and add pSelectableRow directive
            whose value is the rowData to the rows that can be selected. Additionally if you prefer double click use pSelectableRowDblClick directive instead and
            to disable selection events on a particular row use pSelectableRowDisabled. In both cases optional
            pSelectableRowIndex property is avaiable to access the row index. By default each row click adds or removes the row from the selection, if you prefer a classic
            metaKey based selection approach enable metaKeySelection true so that multiple selection or unselection of a row requires metaKey to be pressed. Note that, on touch enabled
            devices, metaKey based selection is turned off automatically as there is no metaKey in devices such as mobile phones.</p>

            <p>Alternative to the row click, radiobutton or checkbox elements can be used to implement row selection.</p>

            <p>When resolving if a row is selected, by default Table compares selection array with the datasource which may cause a performance issue with huge datasets that do not use pagination.
                If available the fastest way is to use dataKey property that identifies a unique row so that Table can avoid comparing arrays as internally a map instance is used instead of looping arrays, on the other hand
                if dataKey cannot be provided consider using compareSelectionBy property as "equals" which uses reference comparison instead of the default "deepEquals" comparison. Latter is slower since it checks all properties.
            </p>

            <p>In single mode, selection binding is an object reference.</p>
<pre>
<code class="language-typescript" pCode ngNonBindable>
export class DataTableDemo implements OnInit &#123;

    cars: Car[];

    selectedCar: Car;

    constructor(private carService: CarService) &#123; &#125;

    ngOnInit() &#123;
        this.carService.getCarsSmall().then(cars => this.cars = cars);
    &#125;
&#125;
</code>
</pre>

<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [columns]="cols" [value]="cars" selectionMode="single" [(selection)]="selectedCar"&gt;
    &lt;ng-template pTemplate="header" let-columns&gt;
        &lt;tr&gt;
            &lt;th *ngFor="let col of columns"&gt;
                &#123;&#123;col.header&#125;&#125;
            &lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-rowData let-columns="columns"&gt;
        &lt;tr [pSelectableRow]="rowData"&gt;
            &lt;td *ngFor="let col of columns"&gt;
                &#123;&#123;rowData[col.field]&#125;&#125;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>

        <p>In multiple mode, selection binding should be an array. Note that if you require shiftKey based range selection, pass the rowIndex to the SelectableRow directive.</p>
<pre>
<code class="language-typescript" pCode ngNonBindable>
export class DataTableDemo implements OnInit &#123;

    cars: Car[];

    selectedCars: Car[];

    constructor(private carService: CarService) &#123; &#125;

    ngOnInit() &#123;
        this.carService.getCarsSmall().then(cars => this.cars = cars);
    &#125;
&#125;
</code>
</pre>

<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [columns]="cols" [value]="cars" selectionMode="multiple" [(selection)]="selectedCars"&gt;
    &lt;ng-template pTemplate="header" let-columns&gt;
        &lt;tr&gt;
            &lt;th *ngFor="let col of columns"&gt;
                &#123;&#123;col.header&#125;&#125;
            &lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-rowData let-columns="columns" let-rowIndex="rowIndex"&gt;
        &lt;tr [pSelectableRow]="rowData" [pSelectableRowIndex]="rowIndex"&gt;
            &lt;td *ngFor="let col of columns"&gt;
                &#123;&#123;rowData[col.field]&#125;&#125;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>

            <p>Single selection using a radiobutton can be done by using p-tableRadioButton component.</p>
<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [columns]="cols" [value]="cars" [(selection)]="selectedCar" dataKey="vin"&gt;
&lt;ng-template pTemplate="header" let-columns&gt;
    &lt;tr&gt;
        &lt;th style="width: 2.25em"&gt;&lt;/th&gt;
        &lt;th *ngFor="let col of columns"&gt;
            &#123;&#123;col.header&#125;&#125;
        &lt;/th&gt;
    &lt;/tr&gt;
&lt;/ng-template&gt;
&lt;ng-template pTemplate="body" let-rowData let-columns="columns"&gt;
    &lt;tr [pSelectableRow]="rowData"&gt;
        &lt;td&gt;
            &lt;p-tableRadioButton [value]="rowData"&gt;&lt;/p-tableRadioButton&gt;
        &lt;/td&gt;
        &lt;td *ngFor="let col of columns"&gt;
            &#123;&#123;rowData[col.field]&#125;&#125;
        &lt;/td&gt;
    &lt;/tr&gt;
&lt;/ng-template&gt;
&lt;ng-template pTemplate="summary"&gt;
        &lt;div style="text-align: left"&gt;
            Selected Car: &#123;&#123;selectedCar4 ? selectedCar4.vin + ' - ' + selectedCar4.brand + ' - ' + selectedCar4.year + ' - ' + selectedCar4.color: 'none'&#125;&#125;
        &lt;/div&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>

                <p>Similarly p-tableCheckbox and p-tableHeaderCheckbox elements are provide to implement checkbox based multiple selection.</p>
<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [columns]="cols" [value]="cars" [(selection)]="selectedCars" dataKey="vin"&gt;
    &lt;ng-template pTemplate="header" let-columns&gt;
        &lt;tr&gt;
            &lt;th style="width: 2.25em"&gt;
                &lt;p-tableHeaderCheckbox&gt;&lt;/p-tableHeaderCheckbox&gt;
            &lt;/th&gt;
            &lt;th *ngFor="let col of columns"&gt;
                &#123;&#123;col.header&#125;&#125;
            &lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-rowData let-columns="columns"&gt;
        &lt;tr [pSelectableRow]="rowData"&gt;
            &lt;td&gt;
                &lt;p-tableCheckbox [value]="rowData"&gt;&lt;/p-tableCheckbox&gt;
            &lt;/td&gt;
            &lt;td *ngFor="let col of columns"&gt;
                &#123;&#123;rowData[col.field]&#125;&#125;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>

            <p>Both p-tableCheckbox and p-tableRadioButton components can be disabled using their property with the same name to prevent selection of a particular row. In addition, index of the row
                needs to be provided to the checkbox/radiobutton components so that they can be available at the onRowSelect or onRowUnselect events of the Table.
            </p>
<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;ng-template pTemplate="body" let-rowData let-rowIndex="rowIndex" let-columns="columns"&gt;
    &lt;tr [pSelectableRow]="rowData"&gt;
        &lt;td&gt;
            &lt;p-tableCheckbox [value]="rowData" [disabled]="rowData.year > 2010" [index]="rowIndex"&gt;&lt;/p-tableCheckbox&gt;
        &lt;/td&gt;
        &lt;td *ngFor="let col of columns"&gt;
            &#123;&#123;rowData[col.field]&#125;&#125;
        &lt;/td&gt;
    &lt;/tr&gt;
&lt;/ng-template&gt;
</code>
</pre>

            <p>See the <a [routerLink]="['/table/selection']">live example.</a></p>

            <h3>ContextMenu</h3>
            <p>DataTable has exclusive integration with contextmenu component. In order to attach a menu to a datatable, add pContextMenuRow directive to the rows that can be selected with context menu, define a local template
            variable for the menu and bind it to the contextMenu property of the datatable. This enables displaying the menu whenever a row is right clicked. A separate contextMenuSelection
            property is used to get a hold of the right clicked row. For dynamic columns, setting pContextMenuRowDisabled property as true disables context menu for that particular row.</p>

<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [columns]="cols" [value]="cars" [(contextMenuSelection)]="selectedCar" [contextMenu]="cm"&gt;
    &lt;ng-template pTemplate="header" let-columns&gt;
        &lt;tr&gt;
            &lt;th *ngFor="let col of columns"&gt;
                &#123;&#123;col.header&#125;&#125;
            &lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-rowData let-columns="columns"&gt;
        &lt;tr [pContextMenuRow]="rowData"&gt;
            &lt;td *ngFor="let col of columns"&gt;
                &#123;&#123;rowData[col.field]&#125;&#125;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;

&lt;p-contextMenu #cm [model]="items"&gt;&lt;/p-contextMenu&gt;
</code>
</pre>

            <p>By default context menu uses a different property called contextMenuSelection as above, this means when row selection mode is also enabled, the two properties, both selection and contextMenuSelection need to be maintained. 
                In case you prefer to configure Table to manage the same selection property both on row click and context menu, set contextMenuSelectionMode as "joint". Table below has both selectionMode and contextMenu enabled where
                both of these features update the same selection object.</p>

<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [columns]="cols" [value]="cars" selectionMode="single" [(selection)]="selectedCar" [contextMenu]="cm" contextMenuSelectionMode="joint"&gt;
    &lt;ng-template pTemplate="header" let-columns&gt;
        &lt;tr&gt;
            &lt;th *ngFor="let col of columns"&gt;
                &#123;&#123;col.header&#125;&#125;
            &lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-rowData let-columns="columns"&gt;
        &lt;tr [pSelectableRow]="rowData" [pContextMenuRow]="rowData"&gt;
            &lt;td *ngFor="let col of columns"&gt;
                &#123;&#123;rowData[col.field]&#125;&#125;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;

&lt;p-contextMenu #cm [model]="items"&gt;&lt;/p-contextMenu&gt;
</code>
</pre>

            <p>See the <a [routerLink]="['/table/contextmenu']">live example.</a></p>

            <h3>Editing</h3>
            <p>Incell editing is enabled by adding pEditableColumn directive to an editable cell that has a p:cellEditor helper
                component to define the input-output templates for the edit and view modes respectively.</p>
<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [columns]="cols" [value]="cars"&gt;
    &lt;ng-template pTemplate="header" let-columns&gt;
        &lt;tr&gt;
            &lt;th&gt;Vin&lt;/th&gt;
            &lt;th&gt;Year&lt;/th&gt;
            &lt;th&gt;Brand&lt;/th&gt;
            &lt;th&gt;Color&lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-rowData let-columns="columns"&gt;
        &lt;tr&gt;
            &lt;td pEditableColumn&gt;
                &lt;p-cellEditor&gt;
                    &lt;ng-template pTemplate="input"&gt;
                        &lt;input type="text" [(ngModel)]="rowData.vin"&gt;
                    &lt;/ng-template&gt;
                    &lt;ng-template pTemplate="output"&gt;
                        &#123;&#123;rowData.vin&#125;&#125;
                    &lt;/ng-template&gt;
                &lt;/p-cellEditor&gt;
            &lt;/td&gt;
            &lt;td pEditableColumn&gt;
                &lt;p-cellEditor&gt;
                    &lt;ng-template pTemplate="input"&gt;
                        &lt;input type="text" [(ngModel)]="rowData.year" required&gt;
                    &lt;/ng-template&gt;
                    &lt;ng-template pTemplate="output"&gt;
                        &#123;&#123;rowData.year&#125;&#125;
                    &lt;/ng-template&gt;
                &lt;/p-cellEditor&gt;
            &lt;/td&gt;
            &lt;td pEditableColumn&gt;
                &lt;p-cellEditor&gt;
                    &lt;ng-template pTemplate="input"&gt;
                        &lt;input type="text" [(ngModel)]="rowData.brand"&gt;
                    &lt;/ng-template&gt;
                    &lt;ng-template pTemplate="output"&gt;
                        &#123;&#123;rowData.brand&#125;&#125;
                    &lt;/ng-template&gt;
                &lt;/p-cellEditor&gt;
            &lt;/td&gt;
            &lt;td pEditableColumn&gt;
                &lt;p-cellEditor&gt;
                    &lt;ng-template pTemplate="input"&gt;
                        &lt;input type="text" [(ngModel)]="rowData.color"&gt;
                    &lt;/ng-template&gt;
                    &lt;ng-template pTemplate="output"&gt;
                        &#123;&#123;rowData.color&#125;&#125;
                    &lt;/ng-template&gt;
                &lt;/p-cellEditor&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>

            <p>If you require the edited row data and the field at onEditComplete event, bind the data to the pEditableColumn directive and the field to the pEditableColumnField directive</p>
<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;td [pEditableColumn]="rowData" [pEditableColumnField]="'year'"&gt;
</code>
</pre>

            <p>See the <a [routerLink]="['/table/editable']">live example.</a></p>

            <h3>Expandable Rows</h3>
            <p>Row expansion allows displaying detailed content for a particular row. To use this feature, add a template named rowexpansion and
                use the pRowToggler directive whose value is the row data instance on an element of your choice whose click event toggles the expansion. This
            enables providing your custom UI such as buttons, links and so on. Example below uses an anchor with an icon as a toggler. Setting pRowTogglerDisabled as true disables the toggle event for the element.</p>
<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [columns]="cols" [value]="cars" dataKey="vin"&gt;
    &lt;ng-template pTemplate="header" let-columns&gt;
        &lt;tr&gt;
            &lt;th style="width: 2.25em"&gt;&lt;/th&gt;
            &lt;th *ngFor="let col of columns"&gt;
                &#123;&#123;col.header&#125;&#125;
            &lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-rowData let-expanded="expanded" let-columns="columns"&gt;
        &lt;tr&gt;
            &lt;td&gt;
                &lt;a href="#" [pRowToggler]="rowData"&gt;
                    &lt;i [ngClass]="expanded ? 'fa fa-fw fa-chevron-circle-down' : 'fa fa-fw fa-chevron-circle-right'"&gt;&lt;/i&gt;
                &lt;/a&gt;
            &lt;/td&gt;
            &lt;td *ngFor="let col of columns"&gt;
                &#123;&#123;rowData[col.field]&#125;&#125;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="rowexpansion" let-rowData let-columns="columns"&gt;
        &lt;tr&gt;
            &lt;td [attr.colspan]="columns.length + 1"&gt;
                &lt;div class="ui-g ui-fluid" style="font-size:16px;padding:20px"&gt;
                    &lt;div class="ui-g-12 ui-md-3" style="text-align:center"&gt;
                        &lt;img [attr.alt]="rowData.brand" src="assets/showcase/images/demo/car/&#123;&#123;rowData.brand&#125;&#125;.png"&gt;
                    &lt;/div&gt;
                    &lt;div class="ui-g-12 ui-md-9"&gt;
                        &lt;div class="ui-g"&gt;
                            &lt;div class="ui-g-12"&gt;
                                &lt;b&gt;Vin:&lt;/b&gt; &#123;&#123;rowData.vin&#125;&#125;
                            &lt;/div&gt;
                            &lt;div class="ui-g-12"&gt;
                                &lt;b&gt;Vin:&lt;/b&gt; &#123;&#123;rowData.color&#125;&#125;
                            &lt;/div&gt;
                            &lt;div class="ui-g-12"&gt;
                                &lt;b&gt;Brand:&lt;/b&gt; &#123;&#123;rowData.brand&#125;&#125;
                            &lt;/div&gt;
                            &lt;div class="ui-g-12"&gt;
                                &lt;b&gt;Color:&lt;/b&gt; &#123;&#123;rowData.color&#125;&#125;
                            &lt;/div&gt;
                        &lt;/div&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>

            <p>Multiple rows can be expanded at the same time, if you prefer a single row expansion at any time set rowExpandMode property to "single". All rows
                are collapsed initially and providing expandedRowKeys property whose value is the dataKeys of the rows to be expanded enables rendering these rows as expanded. A dataKey must be defined
                for this feature.</p>

<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [columns]="cols" [value]="cars" dataKey="vin" [expandedRowKeys]="expandedRows"&gt;
   ...
&lt;/p-table&gt;
</code>
</pre>

            <p>See the <a [routerLink]="['/table/rowexpansion']">live example.</a></p>

            <h3>Column Resize</h3>
            <p>Columns can be resized using drag drop by setting the resizableColumns to true. There are two resize modes; "fit" and "expand". Fit is the default one and
            the overall table width does not change when a column is resized. In "expand" mode, table width also changes along with the column width. onColumnResize
            is a callback that passes the resized column header as a parameter. For dynamic columns, setting pResizableColumnDisabled property as true disables resizing for that particular column.
            </p>

<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [columns]="cols" [value]="cars" [resizableColumns]="true"&gt;
    &lt;ng-template pTemplate="header" let-columns&gt;
        &lt;tr&gt;
            &lt;th *ngFor="let col of columns" pResizableColumn&gt;
                &#123;&#123;col.header&#125;&#125;
            &lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-rowData let-columns="columns"&gt;
        &lt;tr&gt;
            &lt;td *ngFor="let col of columns" class="ui-resizable-column"&gt;
                &#123;&#123;rowData[col.field]&#125;&#125;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>

            <p>It is important to note that when you need to change column widths, since table width is 100%, giving fixed pixel widths does not work well as browsers scale them, instead give percentage widths.</p>
<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [value]="cars" [resizableColumns]="true"&gt;
    &lt;ng-template pTemplate="header"&gt;
        &lt;tr&gt;
            &lt;th style="width:20%"&gt;Vin&lt;/th&gt;
            &lt;th style="width:30%"&gt;Year&lt;/th&gt;
            &lt;th style="width:15%"&gt;Brand&lt;/th&gt;
            &lt;th style="width:35%"&gt;Color&lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-car&gt;
        &lt;tr&gt;
            &lt;td&gt;&#123;&#123;car.vin&#125;&#125;&lt;/td&gt;
            &lt;td&gt;&#123;&#123;car.year&#125;&#125;&lt;/td&gt;
            &lt;td&gt;&#123;&#123;car.brand&#125;&#125;&lt;/td&gt;
            &lt;td&gt;&#123;&#123;car.color&#125;&#125;&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>

            <p><b>Note:</b> Scrollable tables require a column group to support resizing.</p>
<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [columns]="cols" [value]="cars" [scrollable]="true" scrollHeight="200px" [resizableColumns]="true"&gt;
    &lt;ng-template pTemplate="colgroup" let-columns&gt;
        &lt;colgroup&gt;
            &lt;col *ngFor="let col of columns"&gt;
        &lt;/colgroup&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="header" let-columns&gt;
        &lt;tr&gt;
            &lt;th *ngFor="let col of columns" pResizableColumn&gt;
                &#123;&#123;col.header&#125;&#125;
            &lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-rowData let-columns="columns"&gt;
        &lt;tr&gt;
            &lt;td *ngFor="let col of columns" class="ui-resizable-column"&gt;
                &#123;&#123;rowData[col.field]&#125;&#125;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>

            <p>See the <a [routerLink]="['/table/colresize']">live example.</a></p>

            <h3>Column Reordering</h3>
            <p>Columns can be reordered using drag drop by setting the reorderableColumns to true and adding pReorderableColumn directive to the columns that can be dragged. Note that
                columns should be dynamic for reordering to work. For dynamic columns, setting pReorderableColumnDisabled property as true disables reordering for that particular column.</p>
<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [columns]="cols" [value]="cars" [reorderableColumns]="true"&gt;
    &lt;ng-template pTemplate="header" let-columns&gt;
        &lt;tr&gt;
            &lt;th *ngFor="let col of columns" pReorderableColumn&gt;
                &#123;&#123;col.header&#125;&#125;
            &lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-rowData let-columns="columns"&gt;
        &lt;tr&gt;
            &lt;td *ngFor="let col of columns"&gt;
                &#123;&#123;rowData[col.field]&#125;&#125;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>
            <p>See the <a [routerLink]="['/table/colreorder']">live example.</a></p>

            <h3>Rows Reordering</h3>
            <p>Row reordering is enabled by adding pReorderableRow directive with a row index binding to the rows that can be reordered with drag and drop. The optional pReorderableRowDisabled property is available
                to disable dragging for a particular row. In addition, drag handle should get pReorderableRowHandle directive to specify which element is used to initiate the dragging.
            </p>
<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [columns]="cols" [value]="cars"&gt;
    &lt;ng-template pTemplate="header" let-columns&gt;
        &lt;tr&gt;
            &lt;th style="width:2em"&gt;&lt;/th&gt;
            &lt;th *ngFor="let col of columns"&gt;
                &#123;&#123;col.header&#125;&#125;
            &lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-rowData let-columns="columns" let-index="rowIndex"&gt;
        &lt;tr [pReorderableRow]="index"&gt;
            &lt;td&gt;
                &lt;i class="fa fa-bars" pReorderableRowHandle&gt;&lt;/i&gt;
            &lt;/td&gt;
            &lt;td *ngFor="let col of columns"&gt;
                &#123;&#123;rowData[col.field]&#125;&#125;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>
            <p>See the <a [routerLink]="['/table/reorder']">live example.</a></p>

            <h3>Data Export</h3>
            <p>Table can export its data in CSV format using exportCSV() method. By default whole data is exported, if you'd like to export only the selection then pass a config object with selectionOnly property as true. Note that
                columns should be dynamic for export functionality to work and column objects must define field/header properties.
            </p>
<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table #tt[columns]="cols" [value]="cars" selectionMode="multiple" [(selection)]="selectedCars"&gt;
    &lt;ng-template pTemplate="caption"&gt;
        &lt;div class="ui-helper-clearfix"&gt;
            &lt;button type="button" pButton icon="fa-file-o" iconPos="left" label="All Data" (click)="tt.exportCSV()" style="float:left"&gt;&lt;/button&gt;
            &lt;button type="button" pButton icon="fa-file" iconPos="left" label="Selection Only" (click)="tt.exportCSV(&#123;selectionOnly:true&#125;)" style="float:right"&gt;&lt;/button&gt;
        &lt;/div&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="header" let-columns&gt;
        &lt;tr&gt;
            &lt;th *ngFor="let col of columns"&gt;
                &#123;&#123;col.header&#125;&#125;
            &lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-rowData let-columns="columns"&gt;
        &lt;tr [pSelectableRow]="rowData"&gt;
            &lt;td *ngFor="let col of columns"&gt;
                &#123;&#123;rowData[col.field]&#125;&#125;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>

            <p>See the <a [routerLink]="['/table/export']">live example.</a></p>

            <h3>Scrolling</h3>
            <p>DataTable supports both horizontal and vertical scrolling as well as frozen columns and rows. Additionally, virtualScroll mode enables dealing with large datasets by loading data on demand during scrolling.</p>

            <p>Sample below uses vertical scrolling where headers are fixed and data is scrollable.</p>
<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [columns]="cols" [value]="cars" [scrollable]="true" scrollHeight="200px"&gt;
    &lt;ng-template pTemplate="header" let-columns&gt;
        &lt;tr&gt;
            &lt;th *ngFor="let col of columns"&gt;
                &#123;&#123;col.header&#125;&#125;
            &lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-rowData let-columns="columns"&gt;
        &lt;tr&gt;
            &lt;td *ngFor="let col of columns"&gt;
                &#123;&#123;rowData[col.field]&#125;&#125;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>
            <p>In horizontal scrolling on the other hand, it is important to give fixed widths to columns. In general when customizing the column widths of scrollable tables,
                use colgroup as below to avoid misalignment issues as it will apply both the header, body and footer sections which are different separate elements internally.</p>

<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [columns]="cols" [value]="cars" [scrollable]="true" [style]="&#123;width:'500px'&#125;"&gt;
    &lt;ng-template pTemplate="colgroup" let-columns&gt;
        &lt;colgroup&gt;
            &lt;col *ngFor="let col of columns" style="width:250px"&gt;
        &lt;/colgroup&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="header" let-columns&gt;
        &lt;tr&gt;
            &lt;th *ngFor="let col of columns"&gt;
                &#123;&#123;col.header&#125;&#125;
            &lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-rowData let-columns="columns"&gt;
        &lt;tr&gt;
            &lt;td *ngFor="let col of columns"&gt;
                &#123;&#123;rowData[col.field]&#125;&#125;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>

        <p>Horizontal and Vertical scrolling can be combined as well on the same table.</p>
<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [columns]="cols" [value]="cars3" [scrollable]="true" [style]="&#123;width:'500px'&#125;" scrollHeight="200px"&gt;
    &lt;ng-template pTemplate="colgroup" let-columns&gt;
        &lt;colgroup&gt;
            &lt;col *ngFor="let col of columns" style="width:250px"&gt;
        &lt;/colgroup&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="header" let-columns&gt;
        &lt;tr&gt;
            &lt;th *ngFor="let col of columns"&gt;
                &#123;&#123;col.header&#125;&#125;
            &lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-rowData let-columns="columns"&gt;
        &lt;tr&gt;
            &lt;td *ngFor="let col of columns"&gt;
                &#123;&#123;rowData[col.field]&#125;&#125;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>

        <p>Certain rows can be fixed by using the frozenValue property along with the "frozenrows" template.</p>

<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [columns]="cols" [value]="cars4" [frozenValue]="frozenCars" [scrollable]="true" scrollHeight="200px"&gt;
    &lt;ng-template pTemplate="header" let-columns&gt;
        &lt;tr&gt;
            &lt;th *ngFor="let col of columns"&gt;
                &#123;&#123;col.header&#125;&#125;
            &lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="frozenrows" let-rowData let-columns="columns"&gt;
        &lt;tr&gt;
            &lt;td *ngFor="let col of columns"&gt;
                &lt;b&gt;&#123;&#123;rowData[col.field]&#125;&#125;&lt;/b&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-rowData let-columns="columns"&gt;
        &lt;tr&gt;
            &lt;td *ngFor="let col of columns"&gt;
                &#123;&#123;rowData[col.field]&#125;&#125;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>

            <p>Particular columns can be made fixed where others remain scrollable, there are two ways to implement this functionality, either
                define a frozenColumns property if your frozen columns are dynamic or use frozenbody template. The width of the frozen section also
                must be defined with frozenWidth property. Templates including header, body and footer apply to the frozen section as well, however
                if require different content for the frozen section use frozenheader, frozenbody and frozenfooter instead. First example below uses
                dynamic frozen columns and second one demonstrates how to use frozen templates with column grouping.
            </p>

<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [columns]="scrollableCols" [frozenColumns]="frozenCols" [value]="cars5" [scrollable]="true" scrollHeight="200px" frozenWidth="200px"&gt;
    &lt;ng-template pTemplate="colgroup" let-columns&gt;
        &lt;colgroup&gt;
            &lt;col *ngFor="let col of columns" style="width:200px"&gt;
        &lt;/colgroup&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="header" let-columns&gt;
        &lt;tr&gt;
            &lt;th *ngFor="let col of columns"&gt;
                &#123;&#123;col.header&#125;&#125;
            &lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-rowData let-columns="columns"&gt;
        &lt;tr&gt;
            &lt;td *ngFor="let col of columns"&gt;
                &#123;&#123;rowData[col.field]&#125;&#125;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;

&lt;p-table [value]="sales" [scrollable]="true" scrollHeight="150px" frozenWidth="200px"&gt;
    &lt;ng-template pTemplate="frozenheader"&gt;
        &lt;tr&gt;
            &lt;th style="width:200px;height:84px"&gt;Brand&lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="frozenbody" let-sale&gt;
        &lt;tr&gt;
            &lt;td&gt;&#123;&#123;sale.brand&#125;&#125;&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="header"&gt;
        &lt;tr&gt;
            &lt;th colspan="4"&gt;Sale Rate&lt;/th&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;th colspan="2"&gt;Sales&lt;/th&gt;
            &lt;th colspan="2"&gt;Profits&lt;/th&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;th&gt;Last Year&lt;/th&gt;
            &lt;th&gt;This Year&lt;/th&gt;
            &lt;th&gt;Last Year&lt;/th&gt;
            &lt;th&gt;This Year&lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-sale&gt;
        &lt;tr&gt;
            &lt;td&gt;&#123;&#123;sale.lastYearSale&#125;&#125;&lt;/td&gt;
            &lt;td&gt;&#123;&#123;sale.thisYearSale&#125;&#125;&lt;/td&gt;
            &lt;td&gt;&#123;&#123;sale.lastYearProfit&#125;&#125;&lt;/td&gt;
            &lt;td&gt;&#123;&#123;sale.thisYearProfit&#125;&#125;&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>

            <p>When frozen columns are enabled, frozen and scrollable cells may have content with varying height which leads to misalignment. To avoid a performance hit, Table avoids expensive calculations
                to align the row heights as it can be easily done with CSS manually.</p>
<pre>
<code class="language-css" pCode ngNonBindable>
.ui-table .ui-table-frozen-view .ui-table-tbody > tr > td,
.ui-table .ui-table-unfrozen-view .ui-table-tbody > tr > td &#123;
    height: 24px !important;
&#125;
</code>
</pre>

            <p>Virtual Scrolling is used with lazy loading to fetch data on demand during scrolling. For smooth scrolling twice the amount of rows property is loaded
                on a lazy load event. In addition, to avoid performance problems row height is not calculated automatically and should be provided using virtualRowHeight
                property which defaults to 28px, in your row template also assign the height of the row with the same value for smooth scrolling.
                Note that variable row height is not supported due to the nature of the virtual scrolling behavior.
            </p>
<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [columns]="cols" [value]="virtualCars" [scrollable]="true" [rows]="20" scrollHeight="200px" [virtualRowHeight]="30"
    [virtualScroll]="true" (onLazyLoad)="loadDataOnScroll($event)" [lazy]="true" [totalRecords]="totalRecords"&gt;
    &lt;ng-template pTemplate="header" let-columns&gt;
        &lt;tr&gt;
            &lt;th *ngFor="let col of columns"&gt;
                &#123;&#123;col.header&#125;&#125;
            &lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-rowData let-columns="columns"&gt;
        &lt;tr style="height:30px"&gt;
            &lt;td *ngFor="let col of columns"&gt;
                &#123;&#123;rowData[col.field]&#125;&#125;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>

            <p>When column widths need to vary or resizable columns is activated, use colgroup template to avoid misalignment issues and apply percentage values since table width is 100%.</p>

<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [columns]="cols" [value]="cars" [scrollable]="true" scrollHeight="200px"&gt;
    &lt;ng-template pTemplate="colgroup" let-columns&gt;
        &lt;colgroup&gt;
            &lt;col *ngFor="let col of columns" [style.width]="col.width"&gt;
        &lt;/colgroup&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="header" let-columns&gt;
        &lt;tr&gt;
            &lt;th *ngFor="let col of columns"&gt;
                &#123;&#123;col.header&#125;&#125;
            &lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-rowData let-columns="columns"&gt;
        &lt;tr&gt;
            &lt;td *ngFor="let col of columns"&gt;
                &#123;&#123;rowData[col.field]&#125;&#125;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>

            <p>See the <a [routerLink]="['/table/scroll']">live example.</a></p>

            <h3>Lazy Loading</h3>
            <p>Lazy mode is handy to deal with large datasets, instead of loading the entire data, small chunks of data is loaded by invoking
             onLazyLoad callback everytime paging, sorting and filtering happens. To implement lazy loading,
            enable lazy attribute and provide a method callback using onLazyLoad that actually loads the data from a remote datasource. onLazyLoad gets an event object
            that contains information about how the data should be loaded. It is also important to assign the logical number of rows to totalRecords by doing a projection query for paginator configuration so that paginator
            displays the UI assuming there are actually records of totalRecords size although in reality they aren't as in lazy mode, only the records that are displayed on the current page exist.</p>

            <pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [columns]="cols" [value]="cars" [lazy]="true" (onLazyLoad)="loadCarsLazy($event)" [paginator]="true" [rows]="10" [totalRecords]="totalRecords"&gt;
    &lt;ng-template pTemplate="header" let-columns&gt;
        &lt;tr&gt;
            &lt;th *ngFor="let col of columns"&gt;
                &#123;&#123;col.header&#125;&#125;
            &lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-rowData let-columns="columns"&gt;
        &lt;tr&gt;
            &lt;td *ngFor="let col of columns"&gt;
                 &#123;&#123;rowData[col.field]&#125;&#125;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>

<pre>
<code class="language-typescript" pCode ngNonBindable>
loadData(event: LazyLoadEvent) &#123;
    //event.first = First row offset
    //event.rows = Number of rows per page
    //event.sortField = Field name to sort in single sort mode
    //event.sortOrder = Sort order as number, 1 for asc and -1 for dec in single sort mode
    //multiSortMeta: An array of SortMeta objects used in multiple columns sorting. Each SortMeta has field and order properties.
    //filters: Filters object having field as key and filter value, filter matchMode as value
    //globalFilter: Value of the global filter if available
    this.cars = //do a request to a remote datasource using a service and return the cars that match the lazy load criteria
&#125;
</code>
</pre>
            <p>See the <a [routerLink]="['/table/lazy']">live example.</a></p>

            <h3>Responsive</h3>
            <p>Table columns are displayed as stacked in responsive mode if the screen size becomes smaller than a certain breakpoint value. This feature is enabled
            by setting responsive to true and adding an element whose class name is "ui-column-title" to the body cells.</p>
<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [columns]="cols" [value]="cars" [responsive]="true"&gt;
    &lt;ng-template pTemplate="caption"&gt;
        List of Cars
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="header" let-columns&gt;
        &lt;tr&gt;
            &lt;th *ngFor="let col of columns"&gt;
                &#123;&#123;col.header&#125;&#125;
            &lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-rowData let-columns="columns"&gt;
        &lt;tr&gt;
            &lt;td *ngFor="let col of columns"&gt;
                &lt;span class="ui-column-title"&gt;&#123;&#123;col.header&#125;&#125;&lt;/span&gt;
                &#123;&#123;rowData[col.field]&#125;&#125;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="summary"&gt;
        There are &#123;&#123;cars?.length&#125;&#125; cars
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>
            <p>See the <a [routerLink]="['/table/responsive']">live example.</a></p>

            <h3>EmptyMessage</h3>
            <p>When there is no data, emptymessage template can be used to display a message.</p>
<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [value]="cars"&gt;
    &lt;ng-template pTemplate="header"&gt;
        &lt;tr&gt;
            &lt;th&gt;Vin&lt;/th&gt;
            &lt;th&gt;Year&lt;/th&gt;
            &lt;th&gt;Brand&lt;/th&gt;
            &lt;th&gt;Color&lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-car&gt;
        &lt;tr&gt;
            &lt;td&gt;&#123;&#123;car.vin&#125;&#125;&lt;/td&gt;
            &lt;td&gt;&#123;&#123;car.year&#125;&#125;&lt;/td&gt;
            &lt;td&gt;&#123;&#123;car.brand&#125;&#125;&lt;/td&gt;
            &lt;td&gt;&#123;&#123;car.color&#125;&#125;&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="emptymessage" let-columns&gt;
        &lt;tr&gt;
            &lt;td [attr.colspan]="columns.length"&gt;
                No records found
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>

            <h3>Loading Status</h3>
            <p>Table has a loading property, when enabled a spinner icon is displayed to indicate data load.
                An optional loadingIcon property can be passed in case you'd like a different loading icon.</p>
<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [value]="cars" [loading]="loading"&gt;
    &lt;ng-template pTemplate="header"&gt;
        &lt;tr&gt;
            &lt;th&gt;Vin&lt;/th&gt;
            &lt;th&gt;Year&lt;/th&gt;
            &lt;th&gt;Brand&lt;/th&gt;
            &lt;th&gt;Color&lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-car&gt;
        &lt;tr&gt;
            &lt;td&gt;&#123;&#123;car.vin&#125;&#125;&lt;/td&gt;
            &lt;td&gt;&#123;&#123;car.year&#125;&#125;&lt;/td&gt;
            &lt;td&gt;&#123;&#123;car.brand&#125;&#125;&lt;/td&gt;
            &lt;td&gt;&#123;&#123;car.color&#125;&#125;&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>

<pre>
<code class="language-typescript" pCode ngNonBindable>
export class DataTableDemo implements OnInit &#123;

    loading: boolean;

    cars: Car[];

    constructor(private carService: CarService) &#123; &#125;

    ngOnInit() &#123;
        this.loading = true;
        setTimeout(() => &#123;
            this.carService.getCarsSmall().then(cars => this.cars = cars);
            this.loading = false;
        &#125;, 1000);
    &#125;
&#125;
</code>
</pre>

            <h3>Styling Certain Rows and Columns</h3>
            <p>Certain rows and cells can easily be styled using templating features. In example below, the row whose vin property is '123' will get the 'success' style class. Example here
                paint the background of the last cell using a colgroup and highlights rows whose year is older than 2000.
            </p>
<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;p-table [columns]="cols" [value]="cars"&gt;
    &lt;ng-template pTemplate="colgroup" let-columns&gt;
        &lt;colgroup&gt;
            &lt;col&gt;
            &lt;col&gt;
            &lt;col&gt;
            &lt;col style="background-color:#FFD54F !important"&gt;
        &lt;/colgroup&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="header" let-columns&gt;
        &lt;tr&gt;
            &lt;th *ngFor="let col of columns"&gt;
                &#123;&#123;col.header&#125;&#125;
            &lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-rowData let-columns="columns"&gt;
        &lt;tr [ngClass]="rowData.year &gt; 2010 ? 'old-car' : null"&gt;
            &lt;td *ngFor="let col of columns" [ngClass]="rowData[col.field] &lt; 2000 ? 'very-old-car' : null"&gt;
                &#123;&#123;rowData[col.field]&#125;&#125;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>

            <p>See the <a [routerLink]="['/table/style']">live example.</a></p>

            <h3>Performance Tips</h3>
            <ul>
                <li>When selection is enabled use dataKey to avoid deep checking when comparing objects.</li>
                <li>Use rowTrackBy to avoid unnecessary dom operations.</li>
                <li>Prefer lazy loading for large datasets.</li>
            </ul>

            <h3>Properties</h3>
            <div class="doc-tablewrapper">
                <table class="doc-table">
                    <thead>
                        <tr>
                            <th>Name</th>
                            <th>Type</th>
                            <th>Default</th>
                            <th>Description</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td>value</td>
                            <td>array</td>
                            <td>null</td>
                            <td>An array of objects to display.</td>
                        </tr>
                        <tr>
                            <td>columns</td>
                            <td>array</td>
                            <td>null</td>
                            <td>An array of objects to represent dynamic columns.</td>
                        </tr>
                        <tr>
                            <td>frozenColumns</td>
                            <td>array</td>
                            <td>null</td>
                            <td>An array of objects to represent dynamic columns that are frozen.</td>
                        </tr>
                        <tr>
                            <td>frozenValue</td>
                            <td>array</td>
                            <td>null</td>
                            <td>An array of objects to display as frozen.</td>
                        </tr>
                        <tr>
                            <td>style</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Inline style of the component.</td>
                        </tr>
                        <tr>
                            <td>styleClass</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Style class of the component.</td>
                        </tr>
                        <tr>
                            <td>tableStyle</td>
                            <td>any</td>
                            <td>null</td>
                            <td>Inline style of the table.</td>
                        </tr>
                        <tr>
                            <td>tableStyleClass</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Style class of the table.</td>
                        </tr>
                        <tr>
                            <td>paginator</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>When specified as true, enables the pagination.</td>
                        </tr>
                        <tr>
                            <td>rows</td>
                            <td>number</td>
                            <td>null</td>
                            <td>Number of rows to display per page.</td>
                        </tr>
                        <tr>
                            <td>first</td>
                            <td>number</td>
                            <td>0</td>
                            <td>Index of the first row to be displayed.</td>
                        </tr>
                        <tr>
                            <td>totalRecords</td>
                            <td>number</td>
                            <td>null</td>
                            <td>Number of total records, defaults to length of value when not defined.</td>
                        </tr>
                        <tr>
                            <td>pageLinks</td>
                            <td>number</td>
                            <td>null</td>
                            <td>Number of page links to display in paginator.</td>
                        </tr>
                        <tr>
                            <td>rowsPerPageOptions</td>
                            <td>array</td>
                            <td>null</td>
                            <td>Array of integer values to display inside rows per page dropdown of paginator</td>
                        </tr>
                        <tr>
                            <td>alwaysShowPaginator</td>
                            <td>boolean</td>
                            <td>true</td>
                            <td>Whether to show it even there is only one page.</td>
                        </tr>
                        <tr>
                            <td>paginatorPosition</td>
                            <td>string</td>
                            <td>bottom</td>
                            <td>Position of the paginator, options are "top","bottom" or "both".</td>
                        </tr>
                        <tr>
                            <td>sortMode</td>
                            <td>string</td>
                            <td>single</td>
                            <td>Defines whether sorting works on single column or on multiple columns.</td>
                        </tr>
                        <tr>
                            <td>sortField</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Name of the field to sort data by default.</td>
                        </tr>
                        <tr>
                            <td>sortOrder</td>
                            <td>number</td>
                            <td>1</td>
                            <td>Order to sort when default sorting is enabled.</td>
                        </tr>
                        <tr>
                            <td>multiSortMeta</td>
                            <td>array</td>
                            <td>null</td>
                            <td>An array of SortMeta objects to sort the data by default in multiple sort mode.</td>
                        </tr>
                        <tr>
                            <td>rowGroupMode</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Type of the row grouping, valid values are "subheader" and "rowspan".</td>
                        </tr>
                        <tr>
                            <td>defaultSortOrder</td>
                            <td>number</td>
                            <td>1</td>
                            <td>Sort order to use when an unsorted column gets sorted by user interaction.</td>
                        </tr>
                        <tr>
                            <td>customSort</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>Whether to use the default sorting or a custom one using sortFunction.</td>
                        </tr>
                        <tr>
                            <td>sortFunction</td>
                            <td>function</td>
                            <td>null</td>
                            <td>A function to implement custom sorting, refer to sorting section for details.</td>
                        </tr>
                        <tr>
                            <td>selectionMode</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Specifies the selection mode, valid values are "single" and "multiple".</td>
                        </tr>
                        <tr>
                            <td>selection</td>
                            <td>any</td>
                            <td>null</td>
                            <td>Selected row in single mode or an array of values in multiple mode.</td>
                        </tr>
                        <tr>
                            <td>contextMenuSelection</td>
                            <td>any</td>
                            <td>null</td>
                            <td>Selected row with a context menu.</td>
                        </tr>
                        <tr>
                            <td>contextMenuSelectionMode</td>
                            <td>string</td>
                            <td>separate</td>
                            <td>Defines the behavior of context menu selection, in "separate" mode context menu updates contextMenuSelection propertty whereas in joint mode
                                selection property is used instead so that when row selection is enabled, both row selection and context menu selection use the same property.</td>
                        </tr>
                        <tr>
                            <td>dataKey</td>
                            <td>string</td>
                            <td>null</td>
                            <td>A property to uniquely identify a record in data.</td>
                        </tr>
                        <tr>
                            <td>metaKeySelection</td>
                            <td>boolean</td>
                            <td>true</td>
                            <td>Defines whether metaKey is should be considered for the selection. On touch enabled devices, metaKeySelection is turned off automatically.</td>
                        </tr>
                        <tr>
                            <td>rowTrackBy</td>
                            <td>Function</td>
                            <td>null</td>
                            <td>Function to optimize the dom operations by delegating to ngForTrackBy, default algoritm checks for object identity.</td>
                        </tr>
                        <tr>
                            <td>lazy</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>Defines if data is loaded and interacted with in lazy manner.</td>
                        </tr>
                        <tr>
                            <td>lazyLoadOnInit</td>
                            <td>boolean</td>
                            <td>true</td>
                            <td>Whether to call lazy loading on initialization.</td>
                        </tr>
                        <tr>
                            <td>compareSelectionBy</td>
                            <td>string</td>
                            <td>deepEquals</td>
                            <td>Algorithm to define if a row is selected, valid values are "equals" that compares by reference and "deepEquals" that compares all fields.</td>
                        </tr>
                        <tr>
                            <td>csvSeparator</td>
                            <td>string</td>
                            <td>,</td>
                            <td>Character to use as the csv separator.</td>
                        </tr>
                        <tr>
                            <td>exportFilename</td>
                            <td>string</td>
                            <td>download</td>
                            <td>Name of the exported file.</td>
                        </tr>
                        <tr>
                            <td>filters</td>
                            <td>array</td>
                            <td>null</td>
                            <td>An array of FilterMetadata objects to provide external filters.</td>
                        </tr>
                        <tr>
                            <td>filterDelay</td>
                            <td>number</td>
                            <td>300</td>
                            <td>Delay in milliseconds before filtering the data.</td>
                        </tr>
                        <tr>
                            <td>globalFilterFields</td>
                            <td>array</td>
                            <td>null</td>
                            <td>An array of fields as string to use in global filtering.</td>
                        </tr>
                        <tr>
                            <td>expandedRowKeys</td>
                            <td>array</td>
                            <td>null</td>
                            <td>Collection of rows to display as expanded.</td>
                        </tr>
                        <tr>
                            <td>rowExpandMode</td>
                            <td>string</td>
                            <td>multiple</td>
                            <td>Whether multiple rows can be expanded at any time. Valid values are "multiple" and "single".</td>
                        </tr>
                        <tr>
                            <td>scrollable</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>When specifies, enables horizontal and/or vertical scrolling.</td>
                        </tr>
                        <tr>
                            <td>scrollHeight</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Height of the scroll viewport in fixed pixels or percentage.</td>
                        </tr>
                        <tr>
                            <td>virtualScroll</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>Whether the data should be loaded on demand during scroll.</td>
                        </tr>
                        <tr>
                            <td>virtualScrollDelay</td>
                            <td>number</td>
                            <td>500</td>
                            <td>Delay in virtual scroll before doing a call to lazy load.</td>
                        </tr>
                        <tr>
                            <td>virtualRowHeight</td>
                            <td>number</td>
                            <td>28</td>
                            <td>Height of a row to use in calculations of virtual scrolling.</td>
                        </tr>
                        <tr>
                            <td>frozenWidth</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Width of the frozen columns container.</td>
                        </tr>
                        <tr>
                            <td>responsive</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>Defines if the columns should be stacked in smaller screens.</td>
                        </tr>
                        <tr>
                            <td>contextMenu</td>
                            <td>ContextMenu</td>
                            <td>null</td>
                            <td>Local ng-template varilable of a ContextMenu.</td>
                        </tr>
                        <tr>
                            <td>resizableColumns</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>When enabled, columns can be resized using drag and drop.</td>
                        </tr>
                        <tr>
                            <td>columnResizeMode</td>
                            <td>string</td>
                            <td>fit</td>
                            <td>Defines whether the overall table width should change on column resize, valid values are "fit" and "expand".</td>
                        </tr>
                        <tr>
                            <td>reorderableColumns</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>When enabled, columns can be reordered using drag and drop.</td>
                        </tr>
                        <tr>
                            <td>loading</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>Displays a loader to indicate data load is in progress.</td>
                        </tr>
                        <tr>
                            <td>loadingIcon</td>
                            <td>string</td>
                            <td>fa-circle-o-notch</td>
                            <td>The icon to show while indicating data load is in progress.</td>
                        </tr>
                        <tr>
                            <td>rowHover</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>Adds hover effect to rows without the need for selectionMode.</td>
                        </tr>
                        <tr>
                            <td>paginatorDropdownAppendTo</td>
                            <td>any</td>
                            <td>null</td>
                            <td>Target element to attach the paginator dropdown overlay, valid values are "body" or a local ng-template variable of another element.</td>
                        </tr>
                        <tr>
                            <td>autoLayout</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>Whether the cell widths scale according to their content or not.</td>
                        </tr>
                        <tr>
                            <td>resetPageOnSort</td>
                            <td>boolean</td>
                            <td>true</td>
                            <td>When true, resets paginator to first page after sorting.</td>
                        </tr>
                        <tr>
                            <td>exportFunction</td>
                            <td>function</td>
                            <td>null</td>
                            <td>A function to implement custom export. Need to return string value.<br/>
                                event.data: Field data.<br>
                                event.field: Column field.
                            </td>
                        </tr>
                    </tbody>
                </table>
            </div>

            <h3>Events</h3>
            <div class="doc-tablewrapper">
                <table class="doc-table">
                    <thead>
                    <tr>
                        <th>Name</th>
                        <th>Parameters</th>
                        <th>Description</th>
                    </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td>onRowSelect</td>
                            <td>event.originalEvent: Browser event <br>
                                event.data: Selected data <br >
                                event.type: Type of selection, valid values are "row", "radiobutton" and "checkbox"<br>
                                event.index: Index of the row
                            </td>
                            <td>Callback to invoke when a row is selected.</td>
                        </tr>
                        <tr>
                            <td>onRowUnselect</td>
                            <td>event.originalEvent: Browser event <br>
                                event.data: Unselected data <br >
                                event.type: Type of unselection, valid values are "row" and "checkbox"</td>
                            <td>Callback to invoke when a row is unselected.</td>
                        </tr>
                        <tr>
                            <td>onPage</td>
                            <td>event.first: Index of first record in page<br>
                                event.rows: Number of rows on the page</td>
                            <td>Callback to invoke when pagination occurs.</td>
                        </tr>
                        <tr>
                            <td>onSort</td>
                            <td>event.field: Field name of the sorted column<br>
                                event.order: Sort order as 1 or -1<br>
                                event.multisortmeta: Sort metadata in multi sort mode. See multiple sorting section for the structure of this object.</td>
                            <td>Callback to invoke when a column gets sorted.</td>
                        </tr>
                        <tr>
                            <td>onFilter</td>
                            <td>event.filters: Filters object having a field as the property key and an object with value, matchMode as the property value.<br>
                                event.filteredValue: Filtered data after running the filtering.</td>
                            <td>Callback to invoke when data is filtered.</td>
                        </tr>
                        <tr>
                            <td>onLazyLoad</td>
                            <td>event.first = First row offset <br>
                                event.rows = Number of rows per page <br>
                                event.sortField = Field name to sort with <br>
                                event.sortOrder = Sort order as number, 1 for asc and -1 for dec <br>
                                event.multiSortMeta: An array of SortMeta objects used in multiple columns sorting. Each SortMeta has field and order properties.<br>
                                event.filters: FilterMetadata object having field as key and filter value, filter matchMode as value<br>
                                event.globalFilter: Value of the global filter if available</td>
                            <td>Callback to invoke when paging, sorting or filtering happens in lazy mode.</td>
                        </tr>
                        <tr>
                            <td>onRowExpand</td>
                            <td>event.originalEvent: Browser event<br>
                                data: Row data to expand.</td>
                            <td>Callback to invoke when a row is expanded.</td>
                        </tr>
                        <tr>
                            <td>onRowCollapse</td>
                            <td>event.originalEvent: Browser event<br>
                                data: Row data to collapse.</td>
                            <td>Callback to invoke when a row is collapsed.</td>
                        </tr>
                        <tr>
                            <td>onContextMenuSelect</td>
                            <td>event.originalEvent: Browser event <br>
                                event.data: Selected data</td>
                            <td>Callback to invoke when a row is selected with right click.</td>
                        </tr>
                        <tr>
                            <td>onColResize</td>
                            <td>event.element: Resized column header <br>
                                event.delta: Change of width in number of pixels</td>
                            <td>Callback to invoke when a column is resized.</td>
                        </tr>
                        <tr>
                            <td>onColReorder</td>
                            <td>event.dragIndex: Index of the dragged column <br>
                                event.dropIndex: Index of the dropped column <br>
                                event.columns: Columns array after reorder</td>
                            <td>Callback to invoke when a column is reordered.</td>
                        </tr>
                        <tr>
                            <td>onRowReorder</td>
                            <td>event.dragIndex: Index of the dragged row<br>
                                event.dropIndex: Index of the drop location</td>
                            <td>Callback to invoke when a row is reordered.</td>
                        </tr>
                        <tr>
                            <td>onEditInit</td>
                            <td>event.column: Column object of the cell<br>
                                event.data: Row data</td>
                            <td>Callback to invoke when a cell switches to edit mode.</td>
                        </tr>
                        <tr>
                            <td>onEditComplete</td>
                            <td>event.column: Column object of the cell<br>
                                event.data: Row data <br />
                                event.index: Row index</td>
                            <td>Callback to invoke when cell edit is completed.</td>
                        </tr>
                        <tr>
                            <td>onEditCancel</td>
                            <td>event.column: Column object of the cell<br>
                                event.data: Row data <br />
                                event.index: Row index</td>
                            <td>Callback to invoke when cell edit is cancelled with escape key.</td>
                        </tr>
                        <tr>
                            <td>onHeaderCheckboxToggle</td>
                            <td>event.originalEvent: Browser event <br>
                                event.checked: State of the header checkbox</td>
                            <td>Callback to invoke when state of header checkbox changes.</td>
                        </tr>
                    </tbody>
                </table>
            </div>

            <h3>Methods</h3>
            <div class="doc-tablewrapper">
                <table class="doc-table">
                    <thead>
                        <tr>
                            <th>Name</th>
                            <th>Parameters</th>
                            <th>Description</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td>reset</td>
                            <td>-</td>
                            <td>Resets sort, filter and paginator state.</td>
                        </tr>
                        <tr>
                            <td>exportCSV</td>
                            <td>config?.selectionOnly: Exports only the selection.</td>
                            <td>Exports the data in csv format.</td>
                        </tr>
                        <tr>
                            <td>closeCellEdit</td>
                            <td>-</td>
                            <td>Closes the editing cell.</td>
                        </tr>
                    </tbody>
                </table>
            </div>

            <h3>Styling</h3>
            <p>Following is the list of structural style classes, for theming classes visit <a href="#" [routerLink]="['/theming']">theming page</a>.</p>
            <div class="doc-tablewrapper">
                <table class="doc-table">
                    <thead>
                    <tr>
                        <th>Name</th>
                        <th>Element</th>
                    </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td>ui-table</td>
                            <td>Container element.</td>
                        </tr>
                        <tr>
                            <td>ui-table-caption</td>
                            <td>Caption element.</td>
                        </tr>
                        <tr>
                            <td>ui-table-summary</td>
                            <td>Section section.</td>
                        </tr>
                        <tr>
                            <td>ui-sortable-column</td>
                            <td>Sortable column header.</td>
                        </tr>
                        <tr>
                            <td>ui-table-scrollable-header</td>
                            <td>Container of header in a scrollable table.</td>
                        </tr>
                        <tr>
                            <td>ui-table-scrollable-body</td>
                            <td>Container of body in a scrollable table.</td>
                        </tr>
                        <tr>
                            <td>ui-table-scrollable-footer</td>
                            <td>Container of footer in a scrollable table.</td>
                        </tr>
                        <tr>
                            <td>ui-table-responsive</td>
                            <td>Container element of a responsive datatable.</td>
                        </tr>
                        <tr>
                            <td>ui-table-loading</td>
                            <td>Loader mask.</td>
                        </tr>
                        <tr>
                            <td>ui-table-loading-content</td>
                            <td>Loader content.</td>
                        </tr>
                        <tr>
                            <td>ui-table-wrapper</td>
                            <td>Loader content.</td>
                        </tr>
                        <tr>
                            <td>ui-table-scrollable-wrapper</td>
                            <td>Loader content.</td>
                        </tr>
                        <tr>
                            <td>ui-table-resizer-helper</td>
                            <td>Vertical resize indicator bar.</td>
                        </tr>
                        <tr>
                            <td>ui-table-reorder-indicator-top</td>
                            <td>Top indicator of column reordering.</td>
                        </tr>
                        <tr>
                            <td>ui-table-reorder-indicator-top</td>
                            <td>Bottom indicator of column reordering.</td>
                        </tr>
                    </tbody>
                </table>
            </div>

            <h3>Dependencies</h3>
            <p>None.</p>
        </p-tabPanel>

        <p-tabPanel header="Source">
            <a href="https://github.com/primefaces/primeng/tree/master/src/app/showcase/components/table" class="btn-viewsource" target="_blank">
                <i class="fa fa-github"></i>
                <span>View on GitHub</span>
            </a>
<pre>
<code class="language-markup" pCode ngNonBindable>
&lt;h3 class="first"&gt;Basic&lt;/h3&gt;
&lt;p-table [value]="cars"&gt;
    &lt;ng-template pTemplate="header"&gt;
        &lt;tr&gt;
            &lt;th&gt;Vin&lt;/th&gt;
            &lt;th&gt;Year&lt;/th&gt;
            &lt;th&gt;Brand&lt;/th&gt;
            &lt;th&gt;Color&lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-car&gt;
        &lt;tr&gt;
            &lt;td&gt;&#123;&#123;car.vin&#125;&#125;&lt;/td&gt;
            &lt;td&gt;&#123;&#123;car.year&#125;&#125;&lt;/td&gt;
            &lt;td&gt;&#123;&#123;car.brand&#125;&#125;&lt;/td&gt;
            &lt;td&gt;&#123;&#123;car.color&#125;&#125;&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;

&lt;h3&gt;Dynamic Columns&lt;/h3&gt;
&lt;p-table [columns]="cols" [value]="cars"&gt;
    &lt;ng-template pTemplate="header" let-columns&gt;
        &lt;tr&gt;
            &lt;th *ngFor="let col of columns"&gt;
                &#123;&#123;col.header&#125;&#125;
            &lt;/th&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="body" let-rowData let-columns="columns"&gt;
        &lt;tr&gt;
            &lt;td *ngFor="let col of columns"&gt;
                    &#123;&#123;rowData[col.field]&#125;&#125;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ng-template&gt;
&lt;/p-table&gt;
</code>
</pre>

<pre>
<code class="language-typescript" pCode ngNonBindable>
export class TableDemo implements OnInit &#123;

    cars: Car[];

    cols: any[];

    constructor(private carService: CarService) &#123; &#125;

    ngOnInit() &#123;
        this.carService.getCarsSmall().then(cars => this.cars = cars);

        this.cols = [
            &#123; field: 'vin', header: 'Vin' &#125;,
            &#123;field: 'year', header: 'Year' &#125;,
            &#123; field: 'brand', header: 'Brand' &#125;,
            &#123; field: 'color', header: 'Color' &#125;
        ];
    &#125;
&#125;

</code>
</pre>

        </p-tabPanel>
    </p-tabView>
</div>
